/**
 * @module vim-loader
 */

import { EventDispatcher, BaseEvent, Object3D } from 'three'
import { VimDocument, G3d, VimHeader, } from 'vim-format'
import { VimSettings } from './vimSettings'

import {
  ElementMapping,
  ElementMapping2,
  ElementNoMapping
} from './elementMapping'
import { G3dSubset } from './progressive/g3dSubset'

import { VimMeshFactory } from './progressive/MeshFactory.ts'

export interface SubSetBuilderEventMap {
  update: VimSubsetBuilderUpdateEvent
}
type Events = keyof SubSetBuilderEventMap
export class VimSubsetBuilderUpdateEvent implements BaseEvent<Events> {
  type: Events = 'update'
}
interface VimEventMap {
  dispose: DisposeEvent
  loadingUpdate: VimSubsetBuilderUpdateEvent
}
class DisposeEvent implements BaseEvent<keyof VimEventMap> {
  type: keyof VimEventMap = 'dispose'
}


/**
 * Represents a container for the built three.js meshes and the vim data from which they were constructed.
 * Facilitates high-level scene manipulation by providing access to objects.
 */
export class Vim extends EventDispatcher<VimEventMap> {
  factory: VimMeshFactory


  /**
   * The interface to access bim data related to this vim if available.
   */
  readonly bim: VimDocument | undefined

  /**
   * The raw g3d geometry scene definition.
   */
  readonly g3d: G3d

  /**
   * The settings used when this vim was opened.
   */
  readonly settings: VimSettings


  /**
   * The mapping from Bim to Geometry for this vim.
   */
  readonly map: ElementMapping | ElementNoMapping | ElementMapping2

  private readonly _loadedInstances = new Set<number>()
  private readonly _elementToObject = new Map<number, Object>()

  constructor(
    public readonly header: VimHeader,
    g3d: G3d,
    settings: VimSettings,
    map: ElementMapping | ElementNoMapping | ElementMapping2,
    document?: VimDocument,
  ) {
    super()
    this.bim = document
    this.g3d = g3d
    this.factory = new VimMeshFactory(g3d)
    this.settings = settings
    this.map = map ?? new ElementNoMapping()
  }

  /**
   * Retrieves the matrix representation of the Vim object's position, rotation, and scale.
   * @returns The matrix representing the Vim object's transformation.
   */
  getMatrix() {
    return this.settings.matrix
  }




  /**
   * 获得场景元素
   * @returns 
   */
  loadMesh(addCallback: (obj3d: Object3D) => void) {
    const subset = new G3dSubset(this.g3d)
    console.log(this.g3d, '加载子集');


    // 过滤掉已经加载过的
    let isubset = subset.except(this._loadedInstances)!
    if (!isubset.instanceCount) {
      console.log('空子集,忽略.')
      return
    }
    console.log(this._loadedInstances);

    const count = isubset.instanceCount
    for (let i = 0; i < count; i++) {
      // 已经加载过的,添加到缓存中
      this._loadedInstances.add(isubset.getG3dInstanceIndex(i))
    }
    return this.factory.getMeshesBySubset(isubset, addCallback)
  }


  /**
   * Removes the current geometry from the renderer.
   */
  clear() {
    this._elementToObject.clear()
    this._loadedInstances.clear()
    // Clearing this one last because it dispatches the signal
  }

  /**
   * Cleans up and releases resources associated with the vim.
   */
  dispose() {
    this.clear()
    this.dispatchEvent(new DisposeEvent())
  }
}
